/*
 * Copyright (c) 2019 DuckDuckGo
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.duckduckgo.app.statistics

import androidx.lifecycle.LifecycleOwner
import com.duckduckgo.anvil.annotations.ContributesPluginPoint
import com.duckduckgo.app.di.AppCoroutineScope
import com.duckduckgo.app.lifecycle.MainProcessLifecycleObserver
import com.duckduckgo.app.statistics.api.StatisticsUpdater
import com.duckduckgo.app.statistics.pixels.AtbInitializationPluginPixelSender
import com.duckduckgo.app.statistics.store.StatisticsDataStore
import com.duckduckgo.common.utils.DispatcherProvider
import com.duckduckgo.common.utils.plugins.PluginPoint
import com.duckduckgo.di.scopes.AppScope
import com.duckduckgo.privacy.config.api.PrivacyConfigCallbackPlugin
import com.squareup.anvil.annotations.ContributesMultibinding
import dagger.SingleInstanceIn
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withTimeoutOrNull
import logcat.LogPriority.VERBOSE
import logcat.logcat
import javax.inject.Inject

@ContributesMultibinding(
    scope = AppScope::class,
    boundType = MainProcessLifecycleObserver::class,
)
@ContributesMultibinding(
    scope = AppScope::class,
    boundType = PrivacyConfigCallbackPlugin::class,
)
@SingleInstanceIn(AppScope::class)
class AtbInitializer @Inject constructor(
    @AppCoroutineScope private val appCoroutineScope: CoroutineScope,
    private val statisticsDataStore: StatisticsDataStore,
    private val statisticsUpdater: StatisticsUpdater,
    private val listeners: PluginPoint<AtbInitializerListener>,
    private val dispatcherProvider: DispatcherProvider,
    private val pixelSender: AtbInitializationPluginPixelSender,
) : MainProcessLifecycleObserver, PrivacyConfigCallbackPlugin {

    override fun onResume(owner: LifecycleOwner) {
        appCoroutineScope.launch(dispatcherProvider.io()) { refreshAppRetentionAtb() }
    }

    private fun refreshAppRetentionAtb() {
        if (statisticsDataStore.hasInstallationStatistics) {
            statisticsUpdater.refreshAppRetentionAtb()
        }
    }

    override fun onPrivacyConfigDownloaded() {
        if (!statisticsDataStore.hasInstallationStatistics) {
            appCoroutineScope.launch(dispatcherProvider.io()) {
                val preAtbInitPlugins = listeners.getPlugins()
                logcat(VERBOSE) { "AtbInitializer: About to initialize ATB; running ${preAtbInitPlugins.size} pre ATB initialization plugins" }

                preAtbInitPlugins.forEach { plugin ->
                    val pluginName = plugin.javaClass.simpleName
                    logcat(VERBOSE) { "AtbInitializer: Running pre-ATB init plugin [$pluginName]" }

                    withTimeoutOrNull(plugin.beforeAtbInitTimeoutMillis()) {
                        plugin.beforeAtbInit()
                    } ?: onPluginTimeout(pluginName)
                }

                // First time we initializeAtb
                statisticsUpdater.initializeAtb()
            }
        }
    }

    private fun onPluginTimeout(pluginName: String) {
        pixelSender.pluginTimedOut(pluginName)
    }
}

@ContributesPluginPoint(
    scope = AppScope::class,
    boundType = AtbInitializerListener::class,
)
private interface AtbInitializerListenerTrigger
